﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NLite.Messaging;
using NLite.Domain.Events;
using NLite.Data;

namespace NLite.Domain
{
    public static class DomainHelper
    {
        internal static IMessageBus Bus { get; set; }

        private static void Initialize()
        {
            Bus = ServiceLocator.Get<IMessageBus>();
            if (Bus == null)
                throw new ArgumentNullException("Bus");
        }

        /// <summary>
        /// 发布一个领域事件
        /// </summary>
        /// <param name="evnt">领域事件</param>
        /// <returns>返回消息响应结果</returns>
        public static IMessageResponse Publish(IEvent evnt)
        {
            if (Bus == null)
                Initialize();

            var resp = Bus.Publish(null, evnt);

            if (resp.Exception != null)
                throw resp.Exception;

            return resp;
        }

        /// <summary>
        /// 发布一个领域事件
        /// </summary>
        /// <typeparam name="TEvent"></typeparam>
        /// <param name="initEventHandler"></param>
        /// <returns></returns>
        public static IMessageResponse Publish<TEvent>(Action<TEvent> initEventHandler) where TEvent : class,IEvent, new()
        {
            if (Bus == null)
                Initialize();
            var e = new TEvent();
            if (initEventHandler != null)
                initEventHandler(e);
            var resp = Bus.Publish(null, e);
            if (resp.Exception != null)
                throw resp.Exception;

            return resp;
        }

        /// <summary>
        /// 添加领域实体到Database
        /// </summary>
        /// <typeparam name="TDto"></typeparam>
        /// <param name="dto">dto-领域实体的代理</param>
        /// <returns></returns>
        public static bool Insert<TDto>(TDto dto) where TDto : class
        {
            if (Bus == null)
                Initialize();
            var resp = Publish<InsertEvent<TDto>>(e => e.Data = dto);
            var rs = resp.Results;
            if (resp.Canceled)
                return false;

            return rs.OfType<bool?>().All(p => p.HasValue && p.Value);
        }

        /// <summary>
        /// 更新领域实体到Database
        /// </summary>
        /// <typeparam name="TDto"></typeparam>
        /// <param name="dto"></param>
        /// <returns></returns>
        public static bool Update<TDto>(TDto dto) where TDto : class
        {
            if (Bus == null)
                Initialize();
            var resp = Publish(new UpdateEvent<TDto> { Data = dto });

            var rs = resp.Results;
            if (resp.Canceled)
                return false;

            return rs.OfType<bool?>().All(p => p.HasValue && p.Value);
        }

        /// <summary>
        /// 通过实体Id得到领域实体的代理Dto
        /// </summary>
        /// <typeparam name="TDto"></typeparam>
        /// <typeparam name="TEntityId"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public static TDto Get<TDto, TEntityId>(TEntityId id) where TDto : class
        {
            if (Bus == null)
                Initialize();
            TDto entity = null;
            entity = Publish(new QueryEvent<TDto, TEntityId> { Id = id }).Results.OfType<TDto>().FirstOrDefault();
            return entity;
        }

        /// <summary>
        /// 通过实体Id删除对应的实体
        /// </summary>
        /// <typeparam name="TDto"></typeparam>
        /// <typeparam name="TEntityId"></typeparam>
        /// <param name="ids"></param>
        /// <returns></returns>
        public static bool Delete<TDto, TEntityId>(params TEntityId[] ids) where TDto : class
        {
            if (ids == null || ids.Length == 0)
                throw new ArgumentNullException("ids");

            if (Bus == null)
                Initialize();

            //Raise the entity deleted event.
            var resp = Publish(new DeleteEvent<TDto, TEntityId> { Ids = ids });

            var rs = resp.Results;
            if (resp.Canceled)
                return false;

            return rs.OfType<bool?>().All(p => p.HasValue && p.Value);
        }

        /// <summary>
        /// 根据指定的查询上下文得到对应的查询列表
        /// </summary>
        /// <typeparam name="TDto"></typeparam>
        /// <typeparam name="TResultDto"></typeparam>
        /// <param name="ctx"></param>
        /// <returns></returns>
        public static IEnumerable<TResultDto> List<TDto, TResultDto>(QueryContext<TDto> ctx)
        {
            if (Bus == null)
                Initialize();

            var resp = Publish(new QueryEvent<TDto> { Context = ctx });
            var rs = resp.Results.OfType<IEnumerable<TResultDto>>().FirstOrDefault();
            return rs ?? Enumerable.Empty<TResultDto>();
        }

    }
}
